import os
from pathlib import WindowsPath
import tkinter
from tkinter import *
from tkinter.filedialog import askdirectory,askopenfilename
import tkinter.messagebox
from PIL import Image,ImageSequence


Adafruit_SSD1306_1 ='''
#include <Arduino.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
'''
Adafruit_SSD1306_2 ='''
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup() {
   Serial.begin(115200);
    if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }


}
int xx = 0;
int yy = 0;
int tt = 40;
void loop() {
''' 
u8g2_1 = '''
#include <Arduino.h>
#include <U8g2lib.h>
'''
u8g2_2 ='''

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

//U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 22, /* data=*/ 21);   // ESP32 Thing, HW I2C with pin remapping
//U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); //arduino
int xx = 0;
int yy = 0;
int tt = 40;
void setup(void) {
  u8g2.begin();  
  u8g2.setFont(u8g2_font_ncenB14_tr);
}
void loop(void) {
'''

findex = 0
codeIndex = 0
eachFramesTime = []
def saveFps(PIL_Image_object):
    """
    提取并保存GIF图片的每一帧，和每帧延时时间
    将会在当前目录下创建一个 FUCK 文件夹 保存每一帧图片,默认为PNG格式
    """
    if not os.path.exists(os.getcwd()+'\\fuck'):
        os.mkdir(os.getcwd()+'\\fuck')
    PIL_Image_object.seek(0)
    frames = duration = 0
    
    imgiter = ImageSequence.Iterator(PIL_Image_object) # GIF图片流的迭代器
    for frame in imgiter:  # 遍历图片流的每一帧
        try:
            frames += 1
            duration = PIL_Image_object.info['duration'] #获取当前帧的持续时间
            eachFramesTime.append(duration) #将当前帧时间保存到列表
            #print("第%d帧时间%d ms"%(frames,duration))
            PIL_Image_object.seek(PIL_Image_object.tell() + 1) 
            frame.save(os.getcwd()+'\\fuck'+"\\"+str(frames)+'.png') #保存当前帧
            duration = 0
        except EOFError:
            tkinter.messagebox.showwarning(title='OK',message='转换完成')
            
    
    

def remove_transparency(im, bg_colour=(255, 255, 255)):
    '''
    @function:删除PNG图片的透明度
    @parameter: im - Image object
                bg_colour -  BackgroundColor
    '''
    # 仅当图像具有透明度时进行处理
    if im.mode in ('RGBA', 'LA') or (im.mode == 'P' and 'transparency' in im.info):

        # 需要转换为RGBA如果LA格式由于PIL的一个bug
        alpha = im.convert('RGBA').split()[-1]

        # 创建一个新的背景图像的马特色.
        # 必须是RGBA，因为粘贴要求两个图像有相同的格式
        bg = Image.new("RGBA", im.size, bg_colour + (255,))
        bg.paste(im, mask=alpha)
        return bg
    else:
        return im
        
def seleFolder():
    global oldpath      #声明为全局变量
    oldpath = askdirectory() #获取文件路劲
    print(oldpath)
 
def seleOutputFolder():
    global newpath      #声明为全局变量
    newpath = askdirectory()
    os.chdir(newpath)
    print(newpath)

def ma():
    '''
    转为BMP格式
    '''
    for i in (os.listdir(oldpath)):
        if i.lower().split('.')[-1] == 'png' or i.lower().split('.')[-1] == 'jpg': #判断图片格式是否为 png 或 jpg
            imgName = i.lower().split('.')[0]  #获取文件名
            i = oldpath  + '\\'+i
            if i.lower().split('.')[-1] == 'jpg':
                img = Image.open(i) #打开图片
                img = remove_transparency(img) #透明度处理
                img.save(os.path.join(newpath,imgName+'.bmp'),'bmp')

            if i.lower().split('.')[-1] == 'png':
                img = Image.open(i).convert("1")  #打开图片
                img.save(os.path.join(newpath,imgName+'.bmp'),'bmp')
    
    tkinter.messagebox.showwarning(title='OK',message='转换完成')
    print("转换完成!")

def resizeImg():
    '''
    重置大小
    '''
    new_size = (48,48)
    #print(os.listdir(newpath))
    file = os.listdir(os.getcwd()+"\\"+"fuck") # 获取路径下的所有文件
    file.sort(key= lambda x:int(x[:-4])) # 按照文件名 排序
    os.chdir(os.getcwd()+"\\"+"fuck") # 切换工作目录
    print(file)
    index1 = 0 
    for each in file:
        index1 = index1 + 1
        image = Image.open(each)
        new_image = image.resize(new_size)
        new_image.save(str(index1) + '.png','png')
        #os.remove(each)
    tkinter.messagebox.showwarning(title='ok',message='重置完成')    

def bmp2hex():
    filename = entry.get()
    outPutFile = newpath + "\\" + filename + ".h"
    global codeIndex
    codeIndex = 0
    for i in (os.listdir(newpath)):
        codeIndex = codeIndex+1
        img = Image.open(i)
        (width,height) = img.size           #获取图片的宽 高信息
        list1 = []
        list2 = []
        for w in range(height):
            for h in range(width):
                pixel=img.getpixel((h,w))  #获取图片的像素点
                if CheckVar1.get() == 0: # 01反转
                    if pixel == 255:
                        pixel = 1
                    else:
                        pixel = 0
                    list1.append(pixel)   #当前像素值添加到列表里
                else:
                    if pixel == 255:
                        pixel = 0
                    else:
                        pixel = 1
                    list1.append(pixel)   #当前像素值添加到列表里
            list2.append(list1.copy())
            list1.clear()
        while len(list2[0])%8 != 0:      #判断是否为8的倍数,不足补0
            for i in range(len(list2)): #循环每一行
                list2[i].append(0)  #末尾补0
        lenth = len(list2[0])//8
        #print(lenth)
        j=0
        k=0
        l1 = []
        num = 0
        res = ''
        column = 0
        f = open(outPutFile,'a+')
        f.write('\nconst unsigned char PROGMEM '+ filename +str(codeIndex)+'[] = {\n')
        f.close()
        for m in range(len(list2)):      #行循环
                for i in range(lenth):   #列循环
                        j = j+7
                        l1 = list2[m][k:j+1] #提取8位
                        if CheckVar2.get()==1: #是否选中字节倒叙
                            l1.reverse()        #列表翻转(字节倒叙)   

                        for q in range(len(l1)):
                            num = num | l1[q]<<7-q  #合并8位单独数字

                        res = '0x' + str(hex(num))[2:].zfill(2)+"," #格式化为0x00样式                     
                        f = open(outPutFile,'a+')
                        f.write(res)
                        f.close()
                        column = column + 1
                        if column>=12:   #每行个数控制,达到位数时换行
                            f =  open(outPutFile,'a+')
                            f.write('\n')
                            f.close()
                            column = 0
                        num = 0 
                        k = j+1
                        j = j+1
                        findex = codeIndex

                j=0
                k=0
                l1 = []
        f = open(outPutFile,'a+')
        f.write('};')
        f.close()
    tkinter.messagebox.showwarning(title='ok',message='保存完成')

def bmp2hex2():
    filename = entry.get()
    global codeIndex
    codeIndex = 0
    file = os.listdir(newpath)
    file.sort(key= lambda x:int(x[:-4])) # 按照文件名 排序
    print(file)
    outPutFile = newpath + "\\" + filename + ".h"
    f = open(outPutFile,'a+')
    f.write('\nconst unsigned char PROGMEM '+ filename +'[][288] = {\n')
    f.close()
    for i in file:
        codeIndex = codeIndex+1
        if i.split('.')[-1] == "h":
            pass
        else:
            img = Image.open(i)
            (width,height) = img.size           #获取图片的宽 高信息
            list1 = []
            list2 = []
            for w in range(height):
                for h in range(width):
                    pixel=img.getpixel((h,w))  #获取图片的像素点
                    if CheckVar1.get() == 0:
                        if pixel == 255:
                            pixel = 1
                        else:
                            pixel = 0
                        list1.append(pixel)   #当前像素值添加到列表里
                    else:
                        if pixel == 255:
                            pixel = 0
                        else:
                            pixel = 1
                        list1.append(pixel)   #当前像素值添加到列表里
                list2.append(list1.copy())
                list1.clear()
            while len(list2[0])%8 != 0:      #判断是否为8的倍数,不足补0
                for i in range(len(list2)): #循环每一行
                    list2[i].append(0)  #末尾补0
            lenth = len(list2[0])//8
            #print(lenth)
            j=0
            k=0
            l1 = []
            num = 0
            res = ''
            column = 0
            f = open(outPutFile,'a+')
            f.write('{')
            f.close()
            for m in range(len(list2)):      #行循环
                    for i in range(lenth):   #列循环
                            j = j+7
                            l1 = list2[m][k:j+1] #提取8位
                            if CheckVar2.get()==1: #是否选中字节倒叙
                                l1.reverse()        #列表翻转(字节倒叙)   

                            for q in range(len(l1)):
                                num = num | l1[q]<<7-q  #合并8位单独数字

                            res = '0x' + str(hex(num))[2:].zfill(2)+"," #格式化为0x00样式                     
                            f = open(outPutFile,'a+')
                            f.write(res)
                            f.close()
                            column = column + 1
                            if column>=12:   #每行个数控制,达到位数时换行
                                f =  open(outPutFile,'a+')
                                f.write('\n')
                                f.close()
                                column = 0
                            num = 0 
                            k = j+1
                            j = j+1
                            findex = codeIndex

                    j=0
                    k=0
                    l1 = []
           
            f = open(outPutFile,'a+')
            f.write('},')
            f.close()
    f = open(outPutFile,'a+')
    f.write('};')
    f.close()
    
    tkinter.messagebox.showwarning(title='ok',message='保存完成')


def selectGifFile():
    global gif_file
    gif_file = askopenfilename(title="选择GIF图片",filetypes=[("GIF Image",'*.gif')])
    os.chdir(os.path.dirname(gif_file))
    #print(gif_file)

def splitGif():
    img = Image.open(gif_file)
    saveFps(img)

def generateArduinoCode():
    arryname = entry.get()
    print('findex',codeIndex)
    if v.get()==1: # Adafruit_SSD1306 code
        outPutFile = newpath + "\\Adafruit_SSD1306code.txt"
        with open(outPutFile,'a+') as f:
            f.write(Adafruit_SSD1306_1+'\n#include <'+arryname+'.h>'+Adafruit_SSD1306_2) # 写入相关头文件
        for i in range(1,codeIndex+1):
            with open(outPutFile,'a+') as f:
                f.write('display.clearDisplay();\ndisplay.drawBitmap(xx, yy,'+ arryname +str(i)+',48,48, 1);\ndisplay.display();\ndelay('+str(eachFramesTime[i])+');\n\n')
            
        with open(outPutFile,'a+') as f:
            f.write("}")
        tkinter.messagebox.showwarning(title='ok',message='操作完成')
    else: # u8g2 code
        outPutFile = newpath + "\\u8g2code.txt"
        with open(outPutFile,'a+') as f:
            f.write(u8g2_1+'\n#include <'+arryname+'.h>'+u8g2_2)
        for i in range(1,codeIndex+1):
            with open(outPutFile,'a+') as f:
                f.write(' u8g2.firstPage();\n do {\n  u8g2.drawXBMP(xx,yy, 48, 48,'+ arryname +str(i)+');\n} while ( u8g2.nextPage() );\n delay('+str(eachFramesTime[i])+');\n\n')

        with open(outPutFile,'a+') as f:
            f.write("}")
        tkinter.messagebox.showwarning(title='ok',message='操作完成')
    


windows = Tk()
windows.title("OLED动图生成,作者:YYM")
windows.geometry('300x500')
windows.resizable(0,0)

text = "分割GIF,转BMP格式,生成 Arduino 代码 \n目前只支持 jpg 或纯黑白的PNG图片 转 bmp  "
L = Label(windows,text=text)
L.pack()

bb1  = Button(windows,text="选择GIF图片",command=selectGifFile)
bb1.pack()

bb2 = Button(windows,text='分割GIF(将会创建FUCK文件夹)',command=splitGif)
bb2.pack()

b4 = Button(windows,text="重置图片大小(48X48,必须选择)",command=resizeImg)
b4.pack()

b1 = Button(windows,text='选择原始文件夹(即FUCK文件夹)',command=seleFolder)
b1.pack()

b2 = Button(windows,text="选择输出文件夹(需要先创建一个空文件夹)",command=seleOutputFolder)
b2.pack()

entry = Entry(windows)
entry.pack()
entry.insert(0,"数组名(必填)")

 
b3 = Button(windows,text="开始格式转换",command=ma)
b3.pack()




b5 = Button(windows,text='输出16进制数组',command=bmp2hex)
b5.pack()

b6 = Button(windows,text='输出16进制二维数组',command=bmp2hex2)
b6.pack()


CheckVar1 = IntVar()
CheckVar2 = IntVar()
check1 = Checkbutton(windows,text="01反转(0xFF → 0x00)",variable=CheckVar1,onvalue=1,offvalue=0)
check1.pack()

check2 = Checkbutton(windows,text="字节倒叙(低位和高位互换,,u8g2库需要勾选此选项)",variable=CheckVar2,onvalue=1,offvalue=0)
check2.pack()

v = IntVar()
v.set(1)
Radiobutton(windows, text="Adafruit_SSD1306", variable=v, value=1).pack()
Radiobutton(windows, text="u8g2", variable=v, value=2).pack()

b7 = Button(windows,text="生成Arduino代码",command=generateArduinoCode)
b7.pack()

if __name__=="__main__":
    mainloop()

